package com.cctc.juc.common.util;

import com.cctc.juc.common.thread.threadpool.holder.CpuIntenseTargetThreadPoolLazyHolder;
import com.cctc.juc.common.thread.threadpool.holder.IoIntenseTargetThreadPoolLazyHolder;
import com.cctc.juc.common.thread.threadpool.holder.MixedTargetThreadPoolLazyHolder;
import com.cctc.juc.common.thread.threadpool.holder.SeqOrScheduledTargetThreadPoolLazyHolder;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * [线程] 工具类。
 */
public class ThreadUtils {

    // --- [线程（常用）方法] --- //

    /**
     * 获取当前线程。
     */
    public static Thread getCurThread() {
        return Thread.currentThread();
    }

    /**
     * 获取当前线程 ID。
     */
    public static long getCurThreadId() {
        return Thread.currentThread().getId();
    }

    /**
     * 获取当前线程名称。
     */
    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }

    /**
     * 获取当前线程中方法调用栈帧的类名称。
     * - level：1 = 当前方法、2 = 上一级方法、...、以此类推。
     */
    public static String getStackClassName(int level) {
        return Thread.currentThread().getStackTrace()[level].getClassName();
    }

    /**
     * 获取当前线程中方法调用栈帧的方法名称。
     * - level：1 = 当前方法、2 = 上一级方法、...、以此类推。
     */
    public static String getStackMethodName(int level) {
        return Thread.currentThread().getStackTrace()[level].getMethodName();
    }

    /**
     * 休眠当前线程。
     */
    public static void sleepSeconds(int second) {
        LockSupport.parkNanos(second * 1000L * 1000L * 1000L);
    }

    /**
     * 休眠当前线程。
     */
    public static void sleepMilliSeconds(int millisecond) {
        LockSupport.parkNanos(millisecond * 1000L * 1000L);
    }

    /**
     * 当前线程 “让出（CPU 时间片）”。
     * - 老版本使用的是 Thread.yeild() 方法；
     * - 新版本使用的是 Thread.sleep(0) 方法。
     * 说明：二者都是希望 “让出” CPU 资源，让其他线程有竞争 CPU 资源的机会，线程状态由 RUNNING 变为 RUNNABLE，但是：
     * - yield() 方法只是给 CPU 提醒该线程愿意暂时释放 CPU 资源，如果 CPU 资源不紧张，会忽略掉这个提醒，且 yield() 方法在执行期间无法捕获中断异常；
     * - sleep() 方法的作用本身就是让该线程进入休眠状态，让出 CPU 资源，所以 Thread.sleep(0) 一定会 “触发操作系统立刻重新进行一次 CPU 竞争”，让其他线程有竞争 CPU 资源的机会，且 sleep() 方法在执行期间可以捕获到中断异常。
     */
    public static void yield() {
        try {
            Thread.sleep(0);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // --- [线程池（常用）内部类 [线程工厂]，及方法 [线程池工厂、优雅终止线程池]] --- //

    /**
     * （自定义）App 应用线程工厂。
     * - 线程名称：app-thread-pool-number-tag（cpu / io / mixed）-number；
     * -（非守护）工作线程；
     * - 所属线程组（group）： System.getSecurityManager().getThreadGroup() 或 Thread.currentThread().getThreadGroup()；
     * - 优先级：NORM_PRIORITY 正常。
     */
    public static class AppThreadFactory implements ThreadFactory {
        private static final AtomicInteger threadPoolNumber = new AtomicInteger(1);
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final String threadTag;

        public AppThreadFactory(String threadTag) {
            SecurityManager securityManager = System.getSecurityManager();
            group = (securityManager != null) ? securityManager.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            this.threadTag = "app-thread-pool-" + threadPoolNumber.getAndIncrement() + "-" + threadTag + "-";
        }

        @Override
        public Thread newThread(Runnable target) {
            Thread thread = new Thread(group, target, threadTag + threadNumber.getAndIncrement());
            if (thread.isDaemon()) thread.setDaemon(false);
            if (thread.getPriority() != Thread.NORM_PRIORITY) thread.setPriority(Thread.NORM_PRIORITY);
            return thread;
        }
    }

    /**
     * 获取 CPU 密集型任务线程池。
     */
    public static ThreadPoolExecutor getCpuIntenseTargetThreadPool() {
        return CpuIntenseTargetThreadPoolLazyHolder.getExecutor();
    }

    /**
     * 获取 I/O 密集型任务线程池。
     */
    public static ThreadPoolExecutor getIoIntenseTargetThreadPool() {
        return IoIntenseTargetThreadPoolLazyHolder.getExecutor();
    }

    /**
     * 获取混合型任务线程池。
     */
    public static ThreadPoolExecutor getMixedTargetThreadPool() {
        return MixedTargetThreadPoolLazyHolder.getExecutor();
    }

    /**
     * 获取调度 “串行化定时” 型任务线程池
     */
    public static ScheduledThreadPoolExecutor getSeqOrScheduledExecutorService() {
        return SeqOrScheduledTargetThreadPoolLazyHolder.getExecutor();
    }

    /**
     * FIFO “串行化” 顺序（单次）执行目标任务。
     */
    public static void scheduleAtSeqExecute(Runnable command) {
        getSeqOrScheduledExecutorService().execute(command);
    }

    /**
     * 延迟（单次）执行目标任务。
     */
    public static void scheduleAtDelayExecute(Runnable command, int delay, TimeUnit unit) {
        getSeqOrScheduledExecutorService().schedule(command, delay, unit);
    }

    /**
     * “定频”（重复）执行目标任务。
     */
    public static void scheduleAtFixedRateExecute(Runnable command, int initialDelay, int period, TimeUnit unit) {
        getSeqOrScheduledExecutorService().scheduleAtFixedRate(command, initialDelay, period, unit);
    }

    /**
     * “定时”（重复）执行目标任务。
     */
    public static void scheduleWithFixedDelayExecute(Runnable command, int initialDelay, int delay, TimeUnit unit) {
        getSeqOrScheduledExecutorService().scheduleWithFixedDelay(command, initialDelay, delay, unit);
    }

    /**
     * 优雅关闭线程池。
     */
    public static void shutdownThreadPoolGracefully(ExecutorService threadPool) {
        if (!(threadPool instanceof ExecutorService) || threadPool.isTerminated()) return;
        try {
            //（有序）停止线程池：拒绝新任务，继续执行工作队列中的任务；
            threadPool.shutdown();
        } catch (SecurityException | NullPointerException e) {
            return;
        }
        try {
            // 等待 60 s，等待工作队列中的任务执行完
            if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                //（立即）停止线程池：取消正在执行中的任务；
                threadPool.shutdownNow();
                // 再次等待 60 s，如果还未终止，可以再次尝试，或则直接放弃
                if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                    System.err.println("线程池任务未正常执行结束");
                }
            }
        } catch (InterruptedException ie) {
            // 捕获异常，重新调用 shutdownNow
            threadPool.shutdownNow();
        }
        // 仍然没有关闭，循环关闭 1000 次，每次等待 10 毫秒
        if (!threadPool.isTerminated()) {
            try {
                for (int i = 0; i < 1000; i++) {
                    if (threadPool.awaitTermination(10, TimeUnit.MILLISECONDS)) break;
                    threadPool.shutdownNow();
                }
            } catch (InterruptedException e) {
                System.err.println(e.getMessage());
            } catch (Throwable e) {
                System.err.println(e.getMessage());
            }
        }
    }

}
